#pragma once
#include <string.h>
#include <iostream>
#include <memory>
#include <cstdlib>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include "Log.hpp"
#include "Commn.hpp"
#include <sys/wait.h>
#include <pthread.h>
#include "ThreadPool.hpp"
#include <functional>

#define BACKLOG 8
const uint16_t gport = 8888;
using namespace LogModule;
using namespace MyThreadPool;
using task_t = std::function<void(void)>;
using hander_t = std::function<std::string(std::string&)>;

sockaddr_in peer;

class TcpServer
{
struct PthreadData
{
    TcpServer* self;
    int fd;
};
public:
    TcpServer(uint16_t port = gport)
        : _port(port),
          _isrunning(false)
    {

    }
    void InitServer()
    {
        _listensockfd = ::socket(AF_INET, SOCK_STREAM, 0); //进行监听
        if (_listensockfd < 0)
        {
            LOG(LogLevel::FATAL) << "create listensockfd error";
            Die(SOCKET_ERROR);
        }
        LOG(LogLevel::INFO) << "create listensockfd success, listensockfd is: " << _listensockfd;

        sockaddr_in local;

        local.sin_addr.s_addr = INADDR_ANY;
        local.sin_family = AF_INET;
        local.sin_port = ::htons(_port);
        socklen_t len = sizeof(local);
        int n = ::bind(_listensockfd, CONV(&local), len);
        if (n < 0)
        {
            LOG(LogLevel::FATAL) << "bind error";
	    Die(BIND_ERROR);
        }
        LOG(LogLevel::INFO) << "bind success";

        // 连接
        int n1 = ::listen(_listensockfd, BACKLOG); //招呼客人进店
        if (n1 < 0)
        {
            LOG(LogLevel::FATAL) << "listen listensocketfd :" << _listensockfd << " error";
            Die(LISTEN_ERROR);
        }
        LOG(LogLevel::INFO) << "listen listensocketfd :" << _listensockfd << " success";

    }
    void RegisterHander(hander_t hander)
    {
        _hander = hander;
    }
    void HandlerRequest(int socketfd)
    {
        LOG(LogLevel::INFO) << "HandlerRequest socketfs is: " << socketfd;
        char inbuffer[4096];
        while (true)
        {
            int n = ::recv(socketfd, inbuffer, sizeof(inbuffer)-1,0);
            if (n > 0)
            {
                inbuffer[n] = 0;
                LOG(LogLevel::INFO) << inbuffer;
                std::string cmdstr = inbuffer;
                std::string returnstr = _hander(cmdstr);
                int n1 = ::send(socketfd, returnstr.c_str(), returnstr.size(),0);
            }
            else if(n == 0)
            {
                std::cout << "client quit: " << socketfd << std::endl;
                break;
            }   
            else return;
        }
        ::close(socketfd); //关闭文件描述符
    }
    static void* PthreadEnter(void*args)
    {
        pthread_detach(pthread_self()); //把自己与主线程分离，主线程不需要管我了。
        PthreadData* data = (PthreadData*)args;
        std::cout << " socketfd: " << data->fd << std::endl;
        data->self->HandlerRequest(data->fd);
        return nullptr;
    }
    void Start()
    {
        _isrunning = true;
        while (_isrunning)
        {
            memset(&peer, 0, sizeof(peer));
            socklen_t len = sizeof(peer);

            LOG(LogLevel::INFO) << "accept ing...";
            int socketfd = accept(_listensockfd, CONV(&peer), &len); //叫一个服务员来招待客人，然后我继续去外面拉客人。
            if (socketfd < 0)
            {
                LOG(LogLevel::WARNING) << "accept fd error, repeat";
                continue;
            }
            //version-0
            // 连接成功
            LOG(LogLevel::INFO) << "accept socketfd success socketfd is: " << socketfd;
            // HandlerRequest(socketfd);
            //version-1 多进程
            // pid_t id = fork();
            // if (id == 0) //子进程
            // {
            //     ::close(_listensockfd); //关闭没有使用的文件描述符
            //     if (fork() > 0) exit(0);
            //     //此时执行当前代码的是孙子进程
            //     HandlerRequest(socketfd);
            //     exit(0);
            // }
            // //pid_t waitpid(pid_t pid, int *_Nullable wstatus, int options);
            // ::close(socketfd);
            // int wid = waitpid(id,nullptr,0);
            // if (wid < 0)
            // {
            //     std::cout << "wait error" << std::endl;
            // }
            //version-2 多线程 (原生线程库)
            // int pthread_create(pthread_t *restrict thread,
            //               const pthread_attr_t *restrict attr,
            //               void *(*start_routine)(void *),
            //               void *restrict arg);
            // PthreadData* data = new PthreadData;
            // int* sockfdp = new int;
            // std::cout << " socketfd: " << socketfd << std::endl;

            // *sockfdp = socketfd;
            // std::cout << " sockfdp: " << *sockfdp << std::endl;
            // data->fd = *sockfdp;
            // data->self = this;
            // pthread_t pid;
            // pthread_create(&pid,nullptr,PthreadEnter,(void*)data);
            //version-3 线程池
            task_t t = [this,socketfd](){
                this->HandlerRequest(socketfd);
            };
            threadpool<task_t>::Getinstance()->Equeue(t);

        }
    }
    void Stop()
    {
        _isrunning = false;
    }
    ~TcpServer()
    {
    }

private:
    int _listensockfd;
    uint16_t _port;
    bool _isrunning;
    hander_t _hander;
};

